package com.higgins.client.components;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Logger;
import com.higgins.client.dataModel.LawFirmDTO;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.SelectElement;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.ChangeListener;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.TextBoxBase;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.HTMLTable.Cell;
import com.higgins.client.GreetingService;
import com.higgins.client.GreetingServiceAsync;
import com.higgins.client.dataModel.CoveringLetterDTO;
import com.higgins.client.dataModel.RecipientDTO;
import com.higgins.client.dataModel.RegionDTO;
import com.higgins.client.dataModel.SectorDTO;
import com.higgins.client.dataModel.StatusDTO;
import com.higgins.client.dataModel.StrategyDTO;
import com.higgins.client.dataModel.StrategyRecipientDTO;
import com.higgins.client.generic.components.GenericColumn;
import com.higgins.client.generic.components.GenericTable;

public class RecipientTable extends GenericTable	{
	private static final Logger log = Logger.getLogger(RecipientTable.class.getName());
	private final GreetingServiceAsync greetingService = GWT
			.create(GreetingService.class);
	private StrategyDTO strategyDTO = null;
	private RegionDTO regionDTO = null;
	private SectorDTO sectorDTO = null;
	
	public RecipientTable(RecipientColumns columns)	{
		super(columns);
	}

	public void update(StrategyDTO strategyDTO, RegionDTO regionDTO, SectorDTO sectorDTO)	{
		this.strategyDTO = strategyDTO;
		this.regionDTO = regionDTO;
		this.sectorDTO = sectorDTO;
		refresh();
//		retrieveDTOs();
	}
	
	@SuppressWarnings("deprecation")
	protected void addObject(int row, int column, Object object)	{
		addString(row, column, object.toString());
	}
	@SuppressWarnings("deprecation")
	protected void makeCellEditable(final int row, final int column)	{
		Widget widget = getWidget(row, column);
		if (widget==null || widget.getClass().equals(Label.class))	{
			String cellText = getText(row, column);
			final GenericColumn genericColumn = genericColumns.getColumn(column);
			final int finalRow = row;
			ensureRowAvailable(row);
	
			MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
			oracle.add("");
			for (Object listItem:genericColumn.getList())	{
				String item = ((LawFirmDTO)listItem).getName();
				oracle.add(item);
			}
			final SuggestBox suggestBox = new SuggestBox(oracle);
			
			suggestBox.setText(cellText);
			suggestBox.getTextBox().setFocus(true);
			suggestBox.getTextBox().setCursorPos(0);
			
			suggestBox.addKeyUpHandler(new KeyUpHandler() {
				@Override
				public void onKeyUp(KeyUpEvent event) {
					int code = event.getNativeKeyCode();
					if (code == KeyCodes.KEY_ENTER)	{
						try	{
							SelectElement selectElement = suggestBox.getElement().cast();
				            selectElement.getOptions().getItem(0).setDisabled(true);
						} catch (Exception e)	{
							
						}
						setWidget(row, column, new Label(suggestBox.getText()));
						setRowUpdateTag(row);
						
						copyLawFirmAddressToRecipient(row, column, suggestBox.getText());
						
			            updateItemCell(finalRow);
	
						if (genericColumns.getColumns().size() > (column + 2))	{
							makeTableEditable(row, (column+2));
						}
			            
					}
					if (KeyCodes.KEY_ESCAPE == code)	{
						setWidget(row, column, new Label(suggestBox.getText()));
					}
	
				}
				private void copyLawFirmAddressToRecipient(int row, int column, String lawFirm)	{
					for (LawFirmDTO dto:(List<LawFirmDTO>)genericColumn.getList())	{
						if (dto.getName().equals(lawFirm))	{
							column++;
							setText(row, column, dto.getAddress());
						}
					}
					
				}
		    });
			setWidget(row, column, suggestBox);
	 		getCellFormatter().addStyleName(row, column, "FlexTable-normCell");		
		}
	}	
	
	private List<List<Object>> convertDTOtoRowArray(List<RecipientDTO> recipientDTOs)	{
		List<List<Object>> rows = new ArrayList<List<Object>>();
		for (RecipientDTO recipientDTO:recipientDTOs)	{
			List<Object> row = new ArrayList<Object>();
			row.add(recipientDTO.getId());
			row.add(recipientDTO.getName());
			row.add(recipientDTO.getLawFirmDTO()!=null?recipientDTO.getLawFirmDTO().getName():"");
			row.add(recipientDTO.getAddress());
			row.add(recipientDTO.getComment());
			row.add("Available");
			row.add("");
			rows.add(row);
		}
		return rows;
	}
	
	public void updateItemCell(int row)	{
		RecipientDTO recipientDTO = new RecipientDTO();
		recipientDTO.setId(getId(row));
		recipientDTO.setName(getText(row, 1));
		recipientDTO.setLawFirmDTO(getLawFirmDTO(row, 2));
		recipientDTO.setAddress(getText(row, 3));
		recipientDTO.setComment(getText(row, 4));
		//recipientDTO.setTimestamp(getDate(row, 5));
		
		if (recipientDTO.getRegionDTO()==null)
			recipientDTO.setRegionDTO(regionDTO);
		
		if (recipientDTO.getSectorDTO()==null)
			recipientDTO.setSectorDTO(sectorDTO);
		
		updateRow(recipientDTO);
	}
	
	protected void retrieveDTOs()	{
		try {
			greetingService.retrieveRecipients(regionDTO, sectorDTO, new AsyncCallback<List<RecipientDTO>>()	{
					@Override
					public void onFailure(Throwable caught) {
						log.info("CoveringLetterDTO: " + caught.toString());
					}

					@Override
					public void onSuccess(List<RecipientDTO> result) {
						loadData(convertDTOtoRowArray(result));
						retrieveStrategyRecipients();
						retrieveLawFirmStrategyRecipients(result);
					}
				});
		} catch (IllegalArgumentException e) {
			log.info("CoveringLetterDTO: " + e.toString());
		} 
	}	
	private void retrieveLawFirmStrategyRecipients(List<RecipientDTO> results)	{
		for (RecipientDTO dto:results)	{
			try {
				greetingService.retrieveLawFirmUnavailableStatus(dto, new AsyncCallback<Long>()	{
						@Override
						public void onFailure(Throwable caught) {
							log.info("retrieveLawFirmStrategyRecipients: " + caught.toString());
						}

						@Override
						public void onSuccess(Long result) {
							setLawFirmStatus(result);
						}
					});
			} catch (IllegalArgumentException e) {
				log.info("retrieveLawFirmStrategyRecipients: " + e.toString());
			} 

		}
	}
	private void setLawFirmStatus(Long result)	{
		if (result!=null)	{
			String statusFieldTitle = "Firm Status"; 
			Integer row = getRow(result);
			setStatusField(statusFieldTitle, row, "Unavailable");
		}
	}
	private void retrieveStrategyRecipients()	{
		try	{
			greetingService.retrieveStrategyRecipients(strategyDTO.getId(), regionDTO.getId(), sectorDTO.getId(), new AsyncCallback<List<StrategyRecipientDTO>>()	{
				@Override
				public void onFailure(Throwable caught) {
					log.info("CoveringLetterDTO: " + caught.toString());
				}

				@Override
				public void onSuccess(List<StrategyRecipientDTO> result) {
					setRecipientCheckBoxes(result);
					setRecipientStatusFields(result);
				}
			});
		} catch (IllegalArgumentException e)	{
			log.info("CoveringLetterDTO: " + e.toString());
		}
	}
	private void updateRow(RecipientDTO recipientDTO)	{
		try {
			greetingService.updateRecipient(recipientDTO, new AsyncCallback<String>()	{
					@Override
					public void onFailure(Throwable caught) {
						log.info("CoveringLetterDTO: " + caught.toString());
					}

					@Override
					public void onSuccess(String result) {
						setRowIdAfterUpdate(result);
					}
				});
		} catch (IllegalArgumentException e) {
			log.info("CoveringLetterDTO: " + e.toString());
		} /*catch (SecurityAccessDeniedException e) {
			log.info("SecurityAccessDeniedException: " + e.toString());
		} 		*/
	}
	public LawFirmDTO getLawFirmDTO(int row, int column)	{
		try	{
			String lawFirm = getText(row, column);
			return getLawFirmDTO(lawFirm);
		} catch (Exception e)	{
			return null;
		}
	}	
	@SuppressWarnings("unchecked")
	public LawFirmDTO getLawFirmDTO(String lawFirm)	{
		for (GenericColumn genericColumn:genericColumns.getColumns())	{
			if (genericColumn.getType()==(LawFirmDTO.class))	{
				if (genericColumn.getList()!=null)	{
					for (LawFirmDTO dto:(List<LawFirmDTO>)genericColumn.getList())	{
						if (dto.getName().equals(lawFirm))	{
							return dto;
						}
					}
				}
			}
		}
		return null;
	}	
	protected void setRecipientCheckBoxes(List<StrategyRecipientDTO> result)	{
		List<Long> recipientIds = new ArrayList<Long>();
		for (StrategyRecipientDTO dto:result)	{
			if (strategyDTO.getId().equals(dto.getStrategyId()))
				recipientIds.add(dto.getRecipientId());
		}
		setCheckBoxes(recipientIds);
	}
	protected void setRecipientStatusFields(List<StrategyRecipientDTO> result)	{
		List<Long> unavailableRecipientsIds = new ArrayList<Long>();
		List<Long> recipientsIds = new ArrayList<Long>();
		List<Integer> statusList = new ArrayList<Integer>();
		for (StrategyRecipientDTO dto:result)	{
			if (strategyDTO.getId().equals(dto.getStrategyId()))	{
				recipientsIds.add(dto.getRecipientId());
				statusList.add(dto.getStatus());
			} else {
				unavailableRecipientsIds.add(dto.getRecipientId());
			}
		}
		String statusFieldTitle = "Recipient";
		setStatusFields(statusFieldTitle, recipientsIds, statusList);
		setUnavailableStatusFields(statusFieldTitle, unavailableRecipientsIds);
	}
	protected void setStatusFields(String statusFieldTitle, List<Long> ids, List<Integer> status)	{
		int rows = getRowCount()-1;
		for (int row = 1; row < rows; row++)	{
			Long recipientId = getId(row);
			if (recipientId!=null && ids.contains(recipientId))	{
				int index = ids.indexOf(recipientId);
				setStatusField(statusFieldTitle, row, status.get(index));
			} else {
				setStatusField(statusFieldTitle, row, "Available");
			}
		}
	}	
	protected void setUnavailableStatusFields(String statusFieldTitle, List<Long> ids)	{
		int rows = getRowCount() -1;
		for (int row = 1; row < rows; row++)	{
			Long recipientId = getId(row);
			if (recipientId!=null && ids.contains(recipientId))	{
				setStatusField(statusFieldTitle, row, "Unavailable");
			} 
		}
	}
	protected void setStatusField(String statusFieldTitle, int row, String status)	{
		int column = getStatusFieldColumn(statusFieldTitle);
		setText(row, column, status);
	}
	protected void setStatusField(String statusFieldTitle, int row, Integer status)	{
		int column = getStatusFieldColumn(statusFieldTitle);
		if (status!=null)	{
			switch (status)	{
			case 0:
				setText(row, column, "None");
				break;
			case 1:
				setText(row, column, "Requested");
				break;
			case 2:
				setText(row, column, "Generated");
				break;
			case 3:
				setText(row, column, "Posted");
				break;
			}
		} else {
			setText(row, column, "");
		}
	}
	protected Integer getStatusFieldColumn(String statusFieldTitle)	{
		for(GenericColumn genericColumn:genericColumns.getColumns())	{
//			if (genericColumn.getType().equals(StatusDTO.class))
				if (genericColumn.getTitle().equals(statusFieldTitle))
					return genericColumn.getIndex();
		}
		return null;
	}
	protected void checkBoxSet(Long id)	{ 
		try {
			StrategyRecipientDTO recipientStrategyDTO = new StrategyRecipientDTO();
			recipientStrategyDTO.setRecipientId(id);
			recipientStrategyDTO.setRegionId(regionDTO.getId());
			recipientStrategyDTO.setSectorId(sectorDTO.getId());
			recipientStrategyDTO.setStrategyId(strategyDTO.getId());
			recipientStrategyDTO.setDisabled(false);
			greetingService.setStrategyRecipient(recipientStrategyDTO, new AsyncCallback<String>()	{
					@Override
					public void onFailure(Throwable caught) {
						log.info("StrategyRecipientDTO: " + caught.toString());
					}

					@Override
					public void onSuccess(String result) {
						// set the status field using setStatusField(row, text)
					}
				});
		} catch (IllegalArgumentException e) {
			log.info("StrategyRecipientDTO: " + e.toString());
		} 		
	}
	protected void checkBoxCleared(Long id)	{
		try {
			StrategyRecipientDTO recipientStrategyDTO = new StrategyRecipientDTO();
			recipientStrategyDTO.setRecipientId(id);
			recipientStrategyDTO.setRegionId(regionDTO.getId());
			recipientStrategyDTO.setSectorId(sectorDTO.getId());
			recipientStrategyDTO.setStrategyId(strategyDTO.getId());
			recipientStrategyDTO.setDisabled(true);
			greetingService.removeStrategyRecipient(recipientStrategyDTO, new AsyncCallback<String>()	{
					@Override
					public void onFailure(Throwable caught) {
						log.info("StrategyRecipientDTO: " + caught.toString());
					}

					@Override
					public void onSuccess(String result) {
						// set the status field using setStatusField(row, text)
					}
				});
		} catch (IllegalArgumentException e) {
			log.info("StrategyRecipientDTO: " + e.toString());
		} 				
	}
	
}